package com.feiyun.service.impl;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.PositiveOrZero;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.feiyun.common.PageParam;
import com.feiyun.util.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.feiyun.common.ftp.SftpUtil;
import com.feiyun.exception.ExceptionTypeEnum;
import com.feiyun.exception.ServiceException;
import com.feiyun.mapper.UploadRecordInfoMapper;
import com.feiyun.mapper.UserFileRelationMapper;
import com.feiyun.mapper.UserMapper;
import com.feiyun.mapper.UserPhotoMapper;
import com.feiyun.model.entity.UploadRecordInfo;
import com.feiyun.model.entity.User;
import com.feiyun.model.entity.UserFileRelation;
import com.feiyun.model.entity.UserPhoto;
import com.feiyun.service.IFileService;

/**
 * 文件处理
 *
 * @author yan
 * @date 2023-03-18
 */
@Service
@Slf4j
@RequiredArgsConstructor
@Transactional
public class FileServiceImpl extends ServiceImpl<UserPhotoMapper, UserPhoto> implements IFileService {

    private final UserPhotoMapper userPhotoMapper;

    private final UserMapper userMapper;

    private final SftpUtil sftpUtil;

    @Value("${sftp.imagePath}")
    private String baseDir;

    @Value("${sftp.frontPath}")
    private String frontPath;

    @Value("${sftp.filePath}")
    private String filePath;

    private static final String IMAGE_PREFIX = "/home/qry";
    @Resource
    private UploadRecordInfoMapper uploadRecordInfoMapper;

    @Resource
    private UserFileRelationMapper userFileRelationMapper;

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public List<UserPhoto> uploadPhotos(UserPhoto entity, List<MultipartFile> files) {
        List<UserPhoto> userPhotoList = new ArrayList<>();
        if (files.isEmpty() || files.size() == 0){
            throw new RuntimeException("后端为接受到图片");
        }
        files.forEach(file -> {
            // 校验文件大小和后缀
            FileUtil.validateFile(file);
            log.debug("{} validate success.", file.getOriginalFilename());

            String newFileName = FileUtil.convertNewFileName(file);
            String photoPath = frontPath + entity.getUserId() + "/" + newFileName;
            entity.setPhotoPath(photoPath);

            // 头像、照片分开处理
            UserPhoto userPhoto = this.processPhotoByType(entity);

            // 上传图片
            try {
                sftpUtil.upload(baseDir + entity.getUserId(), newFileName, file.getInputStream());
            } catch (Exception e) {
                throw new ServiceException(
                        ExceptionTypeEnum.FILE_EXCEPTION_TYPE);
            }
            // 实体作为返回值供前台使用
            userPhotoList.add(userPhoto);
        });

        log.debug("Uploaded file successfully!");
        return userPhotoList;
    }

    private UserPhoto processPhotoByType(UserPhoto userPhotoEntity) {
        if (userPhotoEntity.getIsAvatar()) {
            // 删除旧头像文件
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id", userPhotoEntity.getUserId());
            User user = userMapper.selectOne(queryWrapper);
            String photoPath = user.getAvatarPath();
            if (!StringUtils.isEmpty(photoPath)) {
                photoPath =IMAGE_PREFIX + photoPath;
                try {
                    if (sftpUtil.isExist(photoPath)) {
                        sftpUtil.delete(photoPath);
                        log.error("清理用户照片成功,图片信息：{}", JSONObject.toJSON(user));
                    }
                } catch (Exception e) {
                    log.error("清理用户照片失败,图片信息：{}", JSONObject.toJSON(user));
                    throw new RuntimeException(e);
                }
            }

            // 新增或更新 照片表 中的头像地址
            QueryWrapper<UserPhoto> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", userPhotoEntity.getUserId());
            wrapper.eq("is_avatar", true);
            UserPhoto userPhoto = userPhotoMapper.selectOne(wrapper);
            userMapper.updateAvatarPathById(userPhotoEntity);
            if (userPhoto == null){
                userPhotoMapper.insert(userPhotoEntity);
                return userPhotoEntity;
            }else {
                userPhoto.setPhotoPath(userPhotoEntity.getPhotoPath());
                userPhotoMapper.updateById(userPhoto);
                return userPhoto;
            }
            // 更新 用户表 里的头像地址
        } else {
            // 非头像直接新增，上限6张
            QueryWrapper<UserPhoto> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", userPhotoEntity.getUserId());
            wrapper.eq("is_avatar", false);
            Integer count = userPhotoMapper.selectCount(wrapper);
            if (count >= 6) {
                throw new ServiceException(
                        ExceptionTypeEnum.FILE_EXCEPTION_TYPE);
            }
            UserPhoto userPhoto = new UserPhoto();
            userPhoto.setUserId(userPhotoEntity.getUserId());
            userPhoto.setIsAvatar(false);
            userPhoto.setPhotoPath(userPhotoEntity.getPhotoPath());
            userPhotoMapper.insert(userPhoto);
            return userPhoto;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePhotos(List<Integer> userPhotoIds) {
        userPhotoIds.forEach(super::removeById);
    }

    @Override
    public List<UserPhoto> selectUserPhoto(Integer userId) {
        QueryWrapper<UserPhoto> wrapper = new QueryWrapper<>();
        wrapper.eq(userId != null, "user_id", userId);
        return userPhotoMapper.selectList(wrapper);
    }

    @Override
    public List<UserPhoto> selectUserPhotoByCondition(UserPhoto userPhotoEntity) {
        QueryWrapper<UserPhoto> wrapper = new QueryWrapper<>();
        wrapper.eq(userPhotoEntity.getUserId() != null, "user_id", userPhotoEntity.getUserId());
        wrapper.eq(userPhotoEntity.getIsAvatar() != null, "is_avatar", userPhotoEntity.getIsAvatar());
        return userPhotoMapper.selectList(wrapper);
    }

    @Override
    public Boolean excleUpload(MultipartFile file) {
        //对文件解析
        List<User> uploadUserInfoList = null;
        try {
            uploadUserInfoList = ExcleUtils.parseExcel(file, User.class);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        //添加文件上传记录
        String fileName = file.getOriginalFilename();
        String newFileName = FileUtil.convertNewFileName(file);
        String fileUUid = this.insertUploadInfo(fileName,newFileName);
        log.info("*****本次上传EXCLE文件,文件名为：{},解析成功，一共解析{}条记录", fileName, uploadUserInfoList.size());
        // 入库
        for (User user : Objects.requireNonNull(uploadUserInfoList)) {
            user.setUuid(UUIDUtils.generate32UUID());
            user.setCreateTime(LocalDateUtils.getNowDate());
            user.setSourceFrom("1");
//            user.setConstellation(DateUtils.getConstellation(user.getBirthDay()));
            user.setZodiac(DateUtils.getZodica(user.getBirthDay()));
            this.inserUserInfo(user);
        }
        // 添加到关系表中
        uploadUserInfoList.forEach(user -> {
            UserFileRelation userFileRelation = new UserFileRelation();
            userFileRelation.setFileId(fileUUid);
            userFileRelation.setUserId(user.getId());
            userFileRelationMapper.insert(userFileRelation);
        });
        log.info("*****本次上传EXCLE文件,文件upload名为：{},已入库成功。一共入库{}条用户信息", fileName, uploadUserInfoList.size());
        //保存文件
        try {
            sftpUtil.upload(filePath, newFileName, file.getInputStream());
        } catch (Exception e) {
            throw new ServiceException(
                    ExceptionTypeEnum.FILE_EXCEPTION_TYPE);
        }
        return true;
    }


    //user-insert 方法，但需要try catch 捕获唯一异常 ，之后循环调用
    public void inserUserInfo(User user){
        try {
            user.setUserId(UUIDUtils.generate6UUID());
            userMapper.insert(user);
        }catch (DuplicateKeyException e){
            log.info("本次新增用户信息，用户编号重复，重新新增");
            this.inserUserInfo(user);
        }
        log.info("本次新增用户信息成功");
    }

    /**
     * 文件上传信息列表查询
     *
     * @param
     * @return
     */
    @Override
    public List<UploadRecordInfo> finduploadInfoList() {
        log.info("*****查询文件上传信息列表*****");
        QueryWrapper<UploadRecordInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("is_approved", false);
        wrapper.orderByDesc("upload_time");
        return uploadRecordInfoMapper.selectList(wrapper);
    }

    /**
     * 文件上传信息列表查询
     *
     * @param
     * @return
     */
    @Override
    public Page<UploadRecordInfo> finduploadInfo(PageParam<UploadRecordInfo> uploadRecordInfoPageParam) {
        Page<UploadRecordInfo> page = new Page<>(uploadRecordInfoPageParam.getPageNum(), uploadRecordInfoPageParam.getPageSize());
        QueryWrapper<UploadRecordInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("is_approved", false);
        wrapper.orderByDesc("upload_time");
        return uploadRecordInfoMapper.selectPage(page, wrapper);

    }


    @Override
    public void updateUploadInfo(UploadRecordInfo uploadRecordInfo) {
        // 根据id 修改状态
        uploadRecordInfoMapper.updateById(uploadRecordInfo);
        if (uploadRecordInfo.getIsApproved()) {
            log.info("*****ID为:{}文件审批通过", uploadRecordInfo.getId());
            // 根据id 修改user表中 用户状态
            QueryWrapper<UserFileRelation> wrapper = new QueryWrapper<>();
            wrapper.eq("file_id",uploadRecordInfo.getId());
            List<UserFileRelation> userFileRelations = userFileRelationMapper.selectList(wrapper);
            for (int i = 0; i < userFileRelations.size(); i++) {
                User user = new User();
                user.setId(userFileRelations.get(i).getUserId());
                user.setIsApproved(true);
                userMapper.updateById(user);
            }
        } else {
            log.info("*****ID为:{}文件审批不通过", uploadRecordInfo.getId());
        }
    }


    @Override
    public void downTemplate(HttpServletRequest request, HttpServletResponse response) {
        String fileName = "template.xls";// 设置文件名，根据业务需要替换成要下载的文件名
        if (fileName != null) {
            //设置文件路径
            File file = new File("/home/cloud", fileName);
            if (file.exists()) {
                response.setContentType("application/force-download");// 设置强制下载不打开
                response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名
                byte[] buffer = new byte[1024];
                FileInputStream fis = null;
                BufferedInputStream bis = null;
                try {
                    fis = new FileInputStream(file);
                    bis = new BufferedInputStream(fis);
                    OutputStream os = response.getOutputStream();
                    int i = bis.read(buffer);
                    while (i != -1) {
                        os.write(buffer, 0, i);
                        i = bis.read(buffer);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (bis != null) {
                        try {
                            bis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (fis != null) {
                        try {
                            fis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    @Override
    public void deleteUploadRecordById(String id) {
        uploadRecordInfoMapper.deleteById(id);
        log.info("删除id：{},的excle文件成功", id);
    }

    @Override
    public void deletePictureById(String id) {
        // 根据id删除图片
        UserPhoto userPhoto = userPhotoMapper.selectById(id);
        // 清理图片
        String photoPath = userPhoto.getPhotoPath();
        if (!StringUtils.isEmpty(photoPath)) {
            photoPath =IMAGE_PREFIX + photoPath;
            try {
                if (sftpUtil.isExist(photoPath)) {
                    sftpUtil.delete(photoPath);
                    log.info("清理用户照片成功");
                }
            } catch (Exception e) {
                log.error("清理用户照片失败,图片信息：{}", JSONObject.toJSON(userPhoto));
                throw new RuntimeException(e);
            }
        }
        // 如果是头像，就修改user表里值
        if (userPhoto.getIsAvatar()){
            Integer userId = userPhoto.getUserId();
            User user = new User();
            user.setId(userId);
            user.setAvatarPath("");
            userMapper.updateById(user);
        }
        //清理数据
        userPhotoMapper.deleteById(id);
        // 更新user 表信息


    }

    /**
     * 补充文件上传信息
     *
     * @param fileName
     * @return
     */
    public String insertUploadInfo(String fileName,String newFileName) {
        UploadRecordInfo uploadRecordInfo = new UploadRecordInfo();
        uploadRecordInfo.setFileName(fileName);
        String fileUUid = UUIDUtils.generate32UUID();
        uploadRecordInfo.setId(fileUUid);
        uploadRecordInfo.setUpdateTime(LocalDateUtils.getNowDate());
        uploadRecordInfo.setIsApproved(false);
        uploadRecordInfo.setNewFileName(newFileName);
        uploadRecordInfoMapper.insert(uploadRecordInfo);
        return fileUUid;
    }

}